package com.example.carRental.handler.filter;

import com.example.carRental.entity.LoginUser;
import com.example.carRental.utils.JwtUtil;
import com.example.carRental.utils.RedisCache;
import io.jsonwebtoken.Claims;
import io.netty.util.internal.StringUtil;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

@Component
//单纯的Filter可能会被调用多次。这个由Spring的提供，保证只会从写一次。
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Resource
    private RedisCache redisCache;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//        此过滤器目的是访问是否有权限。
        String token = request.getHeader("token");

//        获取token。若没有token直接放行，等后面的过滤器来处理，因为有一些功能不需要token。如果没有认证状态但却想访问需要认证的功能会被FilterSecurityInterceptor禁止访问。
//        关于为什么要return，你放行了整条过滤连走完之后回头的时候还会往下执行。你return了回来之后就直接结束函数了。
        if (!StringUtils.hasLength(token)) {
            filterChain.doFilter(request, response);
            return;
        }
//        解析token。
        String userId;
        try {
            Claims claims = JwtUtil.parseJWT(token);
            userId = claims.getSubject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("token非法");
        }
//        从redis中获取用户。getCacheObject<>()有泛型，不需要强转。
        LoginUser loginUser = redisCache.getCacheObject(userId);
        if(Objects.isNull(loginUser))throw new RuntimeException("用户未登录");
//        存入SecurityContextHolder。这个提供后面的过滤器获取当前用户信息。
//        获取权限
        List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList(loginUser.getUser().getRole());
//        存入SecurityContextHolder
        UsernamePasswordAuthenticationToken user = new UsernamePasswordAuthenticationToken(loginUser,null,auth);
        SecurityContextHolder.getContext().setAuthentication(user);
//        放行
        filterChain.doFilter(request, response);
    }
}